:- module(lists).
:- export print_list_ / 2.
:- export checklist_body / 3.
:- export maplist_body / 4.
:- export union / 3.
:- export subset / 2.
:- export splice / 3.
:- export shuffle / 2.
:- export print_list / 1.
:- export maplist / 3.
:- export intersection / 3.
:- export halve / 3.
:- export flatten / 2.
:- export checklist / 2.
:- reexport append / 3, delete / 3, length / 2, member / 2, memberchk / 2, nonmember / 2, subtract / 3, reverse / 2 from sepia_kernel.
:- comment(summary, "Predicates for list manipulation").
:- comment(copyright, "Imperial College London and ICL").
:- comment(date, "$Date: 2004/06/10 11:43:35 $").
:- comment(append / 3, [summary : "Succeeds if List3 is the result of appending List2 to List1.\n\n", template : "append(?List1, ?List2, ?List3)", desc : html("   Unifies List3 to the result of appending List2 to List1.  On\n   backtracking append/3 gives all possible solutions for List1 and List2,\n   if both are uninstantiated.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\nappend([],X,X).\nappend([X|L1],L2,[X|L3]):-\n        append(L1,L2,L3).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["?List1" : "List or variable.", "?List2" : "List or variable.", "?List3" : "List or variable."], resat : "   Yes.", fail_if : "   Fails if List3 does not unify with the result of appending List2 to\n   List1.\n\n", eg : "\nSuccess:\n  append([1,2],L2,[1,2,3,4]). (gives L2=[3,4]).\n  append([1,B],L2,[A,2,3,4]). (gives B=2 L2=[3,4] A=1).\n  append([1,2],L2,L3).        (gives L2=_g70 L3=[1,2|_g70]).\n  append([1]),[2,3]),L3).     (gives L3=[1,2,3]).\n\n  [eclipse]: append(L1,L2,[1,2]), writeln((L1,L2)), fail.\n  [] , [1, 2]\n  [1] , [2]\n  [1, 2] , []\n  no (more) solution.\nFail:\n  append(L1,[3],[1,2,3,4]).\n  append(1,L2,[1,2]).\n\n\n", see_also : [union / 3]]).
:- comment(checklist / 2, [summary : "Succeeds if Pred(Elem) succeeds for every element of List.\n\n", template : "checklist(+Pred, +List)", desc : html("   checklist/3 succeeds if for every element of List, the invocation of\n   Pred with one aditional argument which is this element succeeds.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\n:- tool(checklist/3, checklist_body/4).\n\nchecklist_body(_, [], _).\nchecklist_body(Pred, [Head|Tail], M) :-\n    Pred =.. PL,\n    append(PL, [Head], NewPred),\n    Call =.. NewPred,\n    call(Call, M),\n    checklist_body(Pred, Tail, M).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["+Pred" : "Atom or compound term.", "+List" : "List."], resat : "   No.", fail_if : "   Fails if at least for one element of List the invocation of Pred with\n   this additional argument fails.\n\n", eg : "\nSuccess:\n  checklist(integer, [1, 3, 5]).\n  checklist(spy, [var/1, functor/3]).\n\nFail:\n  checklist(current_op(_, _), [+, -, =]).\n  (fails because the precedence of = does not match that of +)\n\n\n\n", see_also : [maplist / 3]]).
:- comment(delete / 3, [summary : "Succeeds if List2 is List1 less an occurence of Element in List1.\n\n", template : "delete(?Element, ?List1, ?List2)", desc : html("   Unifies the list List2 with the list List1 less an occurence of Element.\n   Any alternative solutions are provided on backtracking.\n<P>\n   This predicate can be used to select an element from a list, delete an\n   element or insert it.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\n    delete(A, [A|B], B).\n    delete(A, [B, C|D], [B|E]) :-\n\t    delete(A, [C|D], E).\n</PRE>\n   This predicate does not perform any type testing functions.\n   "), args : ["?Element" : "Prolog term.", "?List1" : "List or variable.", "?List2" : "List or variable."], resat : "   Yes.", fail_if : "   Fails if List2 does not unify with List1 less an occurence of Element.\n\n", eg : "\nSuccess:\n   [eclipse]: delete(X,[1,M,X],L), writeln((M,X,L)), fail.\n   _g66 , 1 , [_g66, 1]\n   _g66 , _g66 , [1, _g66]\n   _g66 , _g72 , [1, _g66]\n   no (more) solution.\n\n   [eclipse]: delete(3,[1,3,5,3],L).\n   L = [1, 5, 3]    More? (;)\n   L = [1, 3, 5]\n   yes.\n\n   [eclipse]: delete(X,L,[a,b]), writeln((X,L)), fail.\n   _g66 , [_g66, a, b]\n   _g66 , [a, _g66, b]\n   _g66 , [a, b, _g66]\n   no (more) solution.\n\n   delete(X,[1,2],L).   (gives X=1 L=[2]; X=2 L=[1]).\nFail:\n   delete(1,[1,2,1,3],[2,3]).\n\n\n\n", see_also : [subtract / 3, member / 2]]).
:- comment(flatten / 2, [summary : "Succeeds if FlatList is the list of all elements in NestedList, as found in\na left-to-right, depth-first traversal of NestedList.\n\n", template : "flatten(+NestedList, ?FlatList)", desc : html("   FlatList is the list built from all the non-list elements of NestedList\n   and the flattened sublists.  The sequence of elements in FlatList is\n   determined by a left-to-right, depth-first traversal of NestedList.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\nflatten(List, Flat) :-\n        flatten(List, Flat, []).\n\nflatten([], Res, Res) :- !.\nflatten([Head|Tail], Res, Cont) :-\n        !,\n        flatten(Head, Res, Cont1),\n        flatten(Tail, Cont1, Cont).\nflatten(Term, [Term|Cont], Cont).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["+NestedList" : "Ground List.", "?FlatList" : "List or variable."], resat : "   No.", fail_if : "   Fails if FlatList does not unify with the flattened version of\n   NestedList.\n\n", eg : "\nSuccess:\n    [eclipse]: flatten([[1,2,[3,4],5],6,[7]], L).\n    L = [1, 2, 3, 4, 5, 6, 7]\n    yes.\n\nFail:\n    [eclipse]: flatten([1,[3],2], [1,2,3]).\n    no.\n\n\n\n", see_also : [sort / 2, sort / 4, length / 2, member / 2]]).
:- comment(halve / 3, [summary : "Split a list in the middle", template : "halve(+List, -Front, -Back)", desc : html("Returns two lists (Front and Back) which can be concatenated to give\n\tthe original List. The length of the sub-lists is half the length of\n\tthe original. If the original length is odd, Front is one longer"), eg : "\thalve([a,b,c,d,e,f], [a,b,c], [d,e,f])\n\thalve([a,b,c,d,e,f,g], [a,b,c,d], [e,f,g])", see_also : [append / 3]]).
:- comment(intersection / 3, [summary : "Succeeds if Common unifies with the list which contains the common elements\nof List1 and List2.\n\n", template : "intersection(+List1, +List2, ?Common)", desc : html("   Common is unified with a list which contains the common elements of\n   List1 and List2.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\nintersection([], _, []).\nintersection([Head|L1tail], L2, L3) :-\n        memberchk(Head, L2),\n        !,\n        L3 = [Head|L3tail],\n        intersection(L1tail, L2, L3tail).\nintersection([_|L1tail], L2, L3) :-\n        intersection(L1tail, L2, L3).\n</PRE>\n   This predicate does not perform any type testing functions.\n<P>\n   This predicate works properly for set operations only, so repeated\n   elements and variable elements should not be used in the lists.\n\t"), args : ["+List1" : "List.", "+List2" : "List.", "?Common" : "List or variable."], resat : "   Yes.", fail_if : "   Fails if Common does not unify with the list which contains the common\n   elements of List1 and List2.\n\n", eg : "\nSuccess:\n   intersection([1,2],[2,3],L).     (gives L=[2]).\n   intersection([a,d],[a,b,c],[a]).\n\nFail:\n   intersection([a,b],[a,b],[b]).\n\n\n", see_also : [subtract / 3, memberchk / 2, union / 3]]).
:- comment(length / 2, [summary : "Succeeds if the length of list List is N.\n\n", template : "length(?List, ?N)", desc : html("   Unifies N with the length of list List.  length/2 can be used to create\n   a list List of length N. The definition of this Prolog library predicate\n   is:\n<PRE>\nlength(List, Length) :-\n        ( var(Length) ->\n          length(List, 0, Length)\n        ;\n          Length >= 0,\n          length1(List, Length) ).\n\nlength([], Length, Length).\nlength([_|L], N, Length) :-\n        N1 is N+1,\n        length(L, N1, Length).\n\nlength1([], 0) :- !.\nlength1([_|L], Length) :-\n        N1 is Length-1,\n        length1(L, N1).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["?List" : "List or variable.", "?N" : "Integer or variable."], resat : "   Yes.", fail_if : "   Fails if the length of list List does not unify with N.\n\n", eg : "\nSuccess:\n  length([1,2,3],N).   (gives N=3).\n  length([1,2,1,X],N). (gives X=_g84; N=4).\n  length(L,2).         (gives L=[_g62,_g72]). % creates list\nFail:\n  length([1,2,3],2).\n\n\n", see_also : [append / 3]]).
:- comment(maplist / 3, [summary : "Succeeds if Pred(Old, New) succeeds for corresponding pairs of elements\nfrom OldList and NewList.\n\n", template : "maplist(+Pred, ?OldList, ?NewList)", desc : html("   Either OldList or NewList should be a proper list.  maplist/3 succeeds\n   if for every corresponding pair of elements Old, New of the two lists\n   OldList and NewList the invocation of Pred with two aditional arguments\n   Old and New succeeds.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\n:- tool(maplist/3, maplist_body/4).\n\nmaplist_body(_, [], [], _).\nmaplist_body(Pred, [H1|T1], [H2|T2], M) :-\n    Pred =.. PL,\n    append(PL, [H1, H2], NewPred),\n    Call =.. NewPred,\n    call(Call, M),\n    maplist_body(Pred, T1, T2, M).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["+Pred" : "Atom or compound term.", "?OldList" : "List or variable.", "?NewList" : "List or variable."], resat : "   No.", fail_if : "   Fails if at least for one pair of corresponding elements of OldList and\n   NewList the invocation of Pred with these two additional arguments\n   fails.\n\n", eg : "\nSuccess:\n  maplist(integer_atom, [1, 2, 3], ['1', '2', '3']).\n  maplist(sin, [0, 1, 2], X).\n      (gives X = [0.0, 0.841471, 0.909297])\n  maplist(get_flag(var/1), [skip, type, spy], [off, built_in, off]).\nFail:\n  maplist(type_of, [1, a, \"a\"], [integer, atom, atom]).\n\n\n\n", see_also : [checklist / 2]]).
:- comment(member / 2, [summary : "Succeeds if Term unifies with a member of the list List.\n\n", template : "member(?Term, ?List)", desc : html("   Tries to unify Term with an element of the list List.\n<P>\n   If Term is a variable and List is a list, all the members of the list\n   List are found on backtracking.\n<P>\n   If List is not instantiated, member/2 binds List to a new partial list\n   containing the element Term.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\n       member(X,[X|_]).\n       member(X,[Y|T]) :- member(X,T).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["?Term" : "Prolog term.", "?List" : "List or variable."], resat : "   Yes.", fail_if : "   Fails if Term does not unify with a member of the list List.\n\n", eg : "\nSuccess:\n      member(q,[1,2,3,p,q,r]).\n      member(q,[1,2,F]).      (gives F=q).\n      member(X,[1,X]).        (gives X=1; X=_g118).\n      member(X,[2,I]).        (gives X=2 I=_g114; X=_g94 I=_g94).\n      member(1,L).            (gives L=[1|_g64];\n                                     L=[_g62,1|_g68] etc).\n\nFail:\n      member(4,[1,2,3]).\n\n\n\n", see_also : [memberchk / 2]]).
:- comment(memberchk / 2, [summary : "Succeeds if Term is a member of the list List.\n\n", template : "memberchk(+Term, ?List)", desc : html("   Tries to unify Term with an element of the list List.\n<P>\n   If List is not instantiated, memberchk/2 binds List to a new partial\n   list containing an element Term.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\nmemberchk(X,[X|_]) :- !.\nmemberchk(X,[_|T]):- memberchk(X,T).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["+Term" : "Prolog term.", "?List" : "List or a variable."], resat : "   No.", fail_if : "   Fails if Term is not a member of the list List.\n\n", eg : "\nSuccess:\n      memberchk(0,[1,B,2]). (gives B=0).\n      memberchk(1,[1,X]).   (gives X=_g76).\n      memberchk(1,X), memberchk(2,X).\n                            (gives X=[1,2|_g98]).\n\nFail:\n      memberchk(0,[1,2,3,4]).\n\n\n\n", see_also : [member / 2]]).
:- comment(nonmember / 2, [summary : "Succeeds if Element is not an element of the list List.\n\n", template : "nonmember(+Element, +List)", desc : html("   Used to check that Element is not a member of the list List.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\nnonmember(Arg,[Arg|_]) :-\n        !,\n        fail.\nnonmember(Arg,[_|Tail]) :-\n        !,\n        nonmember(Arg,Tail).\nnonmember(_,[]).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["+Element" : "Prolog term.", "+List" : "List."], resat : "   No.", fail_if : "   Fails if Element is an element of the list List.\n\n", eg : "\nSuccess:\n  nonmember(q,[1,2,3,4,5,6,7]).\n\nFail:\n  nonmember(1,[1,2,3]).\n  nonmember(q,[1,2,2,X]). % X and q are unifiable\n\n\n\n", see_also : [member / 2, memberchk / 2]]).
:- comment(print_list / 1, [summary : "Print the elements of a list, one per line", template : "print_list(+List)"]).
:- comment(reverse / 2, [summary : "Succeeds if Reversed is the reversed list List.\n\n", template : "reverse(+List, ?Reversed)", desc : html("   The List is reversed and the resulting list is unified with Reverse.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\nreverse(List, Rev) :-\n        reverse(List, Rev, []).\n\nreverse([], L, L).\nreverse([H|T], L, SoFar) :-\n        reverse(T, L, [H|SoFar]).\n</PRE>\n   This predicate does not perform any type testing functions.\n\t"), args : ["+List" : "Ground List.", "?Reversed" : "List or variable."], resat : "   No.", fail_if : "   Fails if Reverse does not unify with the reversed version of List.\n\n", eg : "\nSuccess:\n    [eclipse]: reverse([1,2,3,4,5], X).\n    X = [5, 4, 3, 2, 1]\n    yes.\n\n\n\n\n", see_also : [append / 3, member / 2]]).
:- comment(shuffle / 2, [summary : "Shuffle a list, ie randomize the element order", template : "shuffle(+List, -ShuffledList)", see_also : [msort / 2]]).
:- comment(splice / 3, [summary : "Merge two lists by interleaving the elements", args : ["Odds" : "List or variable", "Evens" : "List or variable", "List" : "Variable or list"], amode : splice(+, +, ?), amode : splice(?, ?, +), desc : html("Create a new list by alternating elements from two input lists,\n    \tstarting with the first. When one input list is longer, its extra\n\telements form the tail of the result list.\n\t<P>\n\tThe reverse mode splice(-,-,+) is nondeterministic, and\n\tthe most balanced solution(s) will be found first."), eg : "?- splice([1,2,3], [a,b,c], X).\nX = [1, a, 2, b, 3, c]\nYes (0.00s cpu)\n\n?- splice([1,2,3], [a,b,c,d,e], X).               \nX = [1, a, 2, b, 3, c, d, e]\nYes (0.00s cpu)\n\n?- splice(A, B, [1,a,2,b,3,c]).\nA = [1, 2, 3]\nB = [a, b, c]\nMore (0.00s cpu) ? ;\nA = [1, 2, 3, c]\nB = [a, b]\nMore (0.00s cpu) ? ;\nA = [1, 2]\nB = [a, b, 3, c]\nMore (0.00s cpu) ? ;\nA = [1, 2, b, 3, c]\nB = [a]\nMore (0.00s cpu) ? ;\nA = [1]\nB = [a, 2, b, 3, c]\nMore (0.00s cpu) ? ;\nA = [1, a, 2, b, 3, c]\nB = []\nMore (0.00s cpu) ? ;\nA = []\nB = [1, a, 2, b, 3, c]\nYes (0.00s cpu)\n", see_also : [merge / 3]]).
:- comment(subset / 2, [summary : "Succeeds if List is the list which contains all elements from SubList in\nthe same order as in SubList.\n\n", template : "subset(?SubList, +List)", desc : html("   Used to test if a specified list contains all elements of another list,\n   or to generate all sublists of a given list.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\n        subset([],[]).\n        subset([X|L],[X|S]) :-\n            subset(L,S).\n        subset(L, [_|S]) :-\n            subset(L,S).\n</PRE>\n   This predicate does not perform any type testing functions.\n<P>\n   This predicate works properly for set operations only, so repeated\n   elements, variable elements and unsorted lists should not be used.\n\t"), args : ["?SubList" : "A term which unifies with a list.", "+List" : "A term which unifies with a list."], resat : "   Yes.", fail_if : "   Fails if SubList does not unify with a list whose elements are all\n   contained in List in the same order as in SubList.\n\n", eg : "\nSuccess:\n      subset([1,3], [1,2,3]).\n      subset(X, [1,3,4]).        % backtracks over all subsets\n\nFail:\n      subset([2,1], [1,2,3]).   % different order\n\n\n\n", see_also : [union / 3, subtract / 3, intersection / 3]]).
:- comment(subtract / 3, [summary : "Succeeds if Remainder is the list which contains those elements of List1\nwhich are not in List2.\n\n", template : "subtract(+List1, +List2, ?Remainder)", desc : html("   Unifies Remainder with a list containing those elements of List1 which\n   are not in List2.\n<P>\n   The definition of this Prolog library Predicate is:\n<PRE>\nsubtract([], _, []).\nsubtract([Head|Tail], L2, L3) :-\n        memberchk(Head, L2),\n        !,\n        subtract(Tail, L2, L3).\nsubtract([Head|Tail1], L2, [Head|Tail3]) :-\n        subtract(Tail1, L2, Tail3).\n</PRE>\n   This predicate does not perform any type testing functions.\n<P>\n   This predicate works properly for set operations only, so repeated\n   elements and variable elements should not be used.\n\t"), args : ["+List1" : "List.", "+List2" : "List.", "?Remainder" : "List or variable."], resat : "   No.", fail_if : "   Fails if if Remainder does not unify with the list which contains those\n   elements of List1 which are not in List2.\n\n", eg : "\nSuccess:\n   subtract([1,2,3,4],[1],R).     (gives R=[2,3,4]).\n   subtract([1,2,3],[3,4],R).     (gives R=[1,2]).\n   subtract([1,1,2,3],[2],[1,1,3]).\nFail:\n   subtract([1,1,2,3],[1],[1,2,3]). % Fails - List2 and\n                                    % Remainder share elements\n\n\n\n", see_also : [intersection / 3, union / 3]]).
:- comment(union / 3, [summary : "Succeeds if Union is the list which contains the union of elements in List1\nand those in List2.\n\n", template : "union(+List1, +List2, ?Union)", desc : html("   Used to create the list of elements in List1 and not in List2, added to\n   those in List2.\n<P>\n   The definition of this Prolog library predicate is:\n<PRE>\nunion([], L, L).\nunion([Head|L1tail], L2, L3) :-\n        memberchk(Head, L2),\n        !,\n        union(L1tail, L2, L3).\nunion([Head|L1tail], L2, [Head|L3tail]) :-\n        union(L1tail, L2, L3tail).\n</PRE>\n   This predicate does not perform any type testing functions.\n<P>\n   This predicate works properly for set operations only, so repeated\n   elements and variable elements should not be used.\n\t"), args : ["+List1" : "List.", "+List2" : "List.", "?Union" : "List or variable."], resat : "   No.", fail_if : "   Fails if Union does not unify with the list which contains the union of\n   elements in List1 and those in List2.\n\n", eg : "\nSuccess:\n      union([1,2,3],[1,3],L).     (gives L=[2,1,3]).\n\nFail:\n      union([1,2,3,2],[1,3],[1,2,3]).  % repeated elements\n\n\n\n", see_also : [subtract / 3, intersection / 3]]).
:- comment(print_list_ / 2, hidden).
:- comment(checklist_body / 3, hidden).
:- comment(maplist_body / 4, hidden).
